package com.heima.wemedia.service.impl;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.heima.common.exception.CustomException;
import com.heima.model.common.dtos.PageResponseResult;
import com.heima.model.common.dtos.ResponseResult;
import com.heima.model.common.enums.AppHttpCodeEnum;
import com.heima.model.wemedia.dtos.WmNewsDto;
import com.heima.model.wemedia.dtos.WmNewsPageReqDto;
import com.heima.model.wemedia.pojos.WmMaterial;
import com.heima.model.wemedia.pojos.WmNews;
import com.heima.model.wemedia.pojos.WmNewsMaterial;
import com.heima.utils.thread.WmThreadLocalUtil;
import com.heima.wemedia.mapper.WmMaterialMapper;
import com.heima.wemedia.mapper.WmNewsMapper;
import com.heima.wemedia.mapper.WmNewsMaterialMapper;
import com.heima.wemedia.service.WmAutoScanService;
import com.heima.wemedia.service.WmNewsService;
import com.heima.wemedia.service.WmTaskService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.validation.constraints.Size;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @author jack
 * @data 2024 9:46
 */
@Service
@Transactional
@Slf4j
public class WmNewsServiceImpl extends ServiceImpl<WmNewsMapper, WmNews> implements WmNewsService {
    @Autowired
    private WmNewsMaterialMapper wmNewsMaterialMapper;
    @Autowired
    private WmMaterialMapper wmMaterialMapper;
    @Autowired
    private WmAutoScanService wmAutoScanService;
    @Autowired
    private WmTaskService wmTaskService;

    /**
     * 分页条件查询文章列表
     *
     * @param reqDto
     * @return
     */
    @Override
    public ResponseResult queryByPageWithConditions(WmNewsPageReqDto reqDto) {
        //1. 参数校验
        if (reqDto == null){
            throw new CustomException(AppHttpCodeEnum.PARAM_INVALID);
        }
        reqDto.checkParam();

        //2. 构建分页对象 -- page
        Page page = new Page(reqDto.getPage(),reqDto.getSize());

        //3. 构建条件对象 -- wrapper
        LambdaQueryWrapper<WmNews> wrapper = Wrappers.<WmNews>lambdaQuery()
                .ge(reqDto.getBeginPubDate() != null, WmNews::getPublishTime, reqDto.getBeginPubDate())
                .le(reqDto.getEndPubDate() != null, WmNews::getPublishTime, reqDto.getEndPubDate())
                .eq(reqDto.getChannelId() != null, WmNews::getChannelId, reqDto.getChannelId())
                .like(StringUtils.isNotBlank(reqDto.getKeyword()), WmNews::getTitle, reqDto.getKeyword())
                .eq(reqDto.getStatus() != null, WmNews::getStatus, reqDto.getStatus())
                .eq(WmNews::getUserId, WmThreadLocalUtil.getUser().getId())
                .orderByDesc(WmNews::getPublishTime);

        //4. 分页条件查询
        page(page,wrapper);

        //5. 封装结果返回
        PageResponseResult result = new PageResponseResult((int)page.getCurrent(),(int) page.getSize(),(int) page.getTotal());
        result.ok(AppHttpCodeEnum.SUCCESS.getCode(),page.getRecords(),AppHttpCodeEnum.SUCCESS.getErrorMessage());
        return result;
    }

    /**
     * 发布文章
     *
     * @param wmNewsDto
     * @return
     */
    @Override
    public ResponseResult submit(WmNewsDto wmNewsDto) {

        //0. 参数校验
        if (wmNewsDto == null || StringUtils.isBlank(wmNewsDto.getContent()))
            throw new CustomException(AppHttpCodeEnum.PARAM_INVALID);

        //数据处理
        WmNews wmNews = new WmNews();
        BeanUtils.copyProperties(wmNewsDto,wmNews);
        if (wmNewsDto.getType() == -1){
            wmNews.setType(null);       //数据库不记录 -1，留着后续处理
        }
        String images = String.join(",", wmNewsDto.getImages());
        wmNews.setImages(images);
        wmNews.setUserId(WmThreadLocalUtil.getUser().getId());

        //1. 新增或修改文章
        saveOrUpdateNews(wmNews);

        //2. 判断是否是草稿，如果是草稿：流程结束
        if (wmNewsDto.getStatus().equals(0)){
            return ResponseResult.okResult(AppHttpCodeEnum.SUCCESS);
        }

        //3. 不是草稿：维护文章和内容图片的关系
        //3.1 解析文章内容，得到所有的内容图片
        List<String> imgUrlsInContent = handleImgByContent(wmNewsDto.getContent());
        //3.2 保存内容图片和文章的关联关系
        saveRelationWithContentImg(wmNews,imgUrlsInContent);

        //4. 不是草稿：维护文章和封面图片的关系
        saveRelationWithCoverImg(wmNews,wmNewsDto,imgUrlsInContent);

        //5. 开启文章的自动审核
        //wmAutoScanService.autoScan(wmNews.getId());

        //5. 异步添加审核文章的任务  -- 发消息
        wmTaskService.addTask(wmNews);

        return ResponseResult.okResult(AppHttpCodeEnum.SUCCESS);
    }

    /**
     * 保存封面图片和文章的关联关系
     * @param wmNews
     * @param wmNewsDto
     * 1. 处理封面类型为自动的情况，产品经理给出的规则如下：
     *      a. 当内容图片数量 >=1 && 当内容图片数量 < 3  : 适配为单图
     *      b. 当内容图片数量 >=3 : 适配为三图
     *      c. 当内容图片数量 <1 : 适配为无图
     *  2. 保存封面图片和文章的关联关系
     */
    private void saveRelationWithCoverImg(WmNews wmNews, WmNewsDto wmNewsDto,List<String> imgUrlsInContent) {

        //获取前端传递过来的封面图片
        List<String> images = wmNewsDto.getImages();

        //1. 处理封面类型为自动的情况
        if (wmNewsDto.getType() == -1){
            //开启适配
            if (imgUrlsInContent != null && imgUrlsInContent.size() >= 1 && imgUrlsInContent.size() < 3){
                wmNews.setType((short)1);   //单图
                images = imgUrlsInContent.stream().limit(1).collect(Collectors.toList());
            }else if (imgUrlsInContent != null && imgUrlsInContent.size() >= 3){
                wmNews.setType((short)3);   //多图
                images = imgUrlsInContent.stream().limit(3).collect(Collectors.toList());
            }else {
                wmNews.setType((short)0);   //无图
            }

            //修改文章信息
            if (images != null && images.size() > 0){
                wmNews.setImages(String.join(",",images));
            }
            updateById(wmNews);

        }
        //2. 保存封面图片和文章的关联关系
        saveRelationWithImg(wmNews,images,(short)1);
    }

    //保存内容图片和文章的关联关系
    private void saveRelationWithContentImg(WmNews wmNews, List<String> imgUrlsInContent) {
       saveRelationWithImg(wmNews,imgUrlsInContent,(short) 0);
    }

    /**
     * 保存图片和文章的关联关系
     * @param wmNews   文章
     * @param imgUrls  图片url集合
     * @param type  0：内容引用； 1：封面引用
     */
    private void saveRelationWithImg(WmNews wmNews, List<String> imgUrls,Short type){
        if (imgUrls != null && imgUrls.size() > 0) {
            //1. 根据图片的url查找图片的id  -- wm_material
            //对图片url去重
            imgUrls = imgUrls.stream().distinct().collect(Collectors.toList());
            List<WmMaterial> wmMaterials = wmMaterialMapper.selectList(Wrappers.<WmMaterial>lambdaQuery().in(WmMaterial::getUrl, imgUrls));
            List<Integer> materialIds = wmMaterials.stream().map(WmMaterial::getId).collect(Collectors.toList());

            //2. 将素材id和文章id一起保存到关系表 -- wm_news_material
            wmNewsMaterialMapper.saveRelationBatch(wmNews.getId(),materialIds,type);
        }
    }

    //提取文章内容中的所有图片
    private List<String> handleImgByContent(String content) {
        List<String> res = new ArrayList<>();

        JSONArray jsonArray = JSONArray.parseArray(content);
        for (Object obj : jsonArray) {
            JSONObject jsonObject = JSONObject.parseObject(obj.toString());
            if ("image".equals(jsonObject.getString("type"))){
                String imgUrl = jsonObject.getString("value");
                res.add(imgUrl);
            }
        }
        return res;
    }

    //新增或修改文章
    private void saveOrUpdateNews(WmNews wmNews) {
        wmNews.setSubmitedTime(new Date());

        if (wmNews.getId() != null){
            //修改
            //1. 清除文章和图片的关联关系
            wmNewsMaterialMapper.delete(Wrappers.<WmNewsMaterial>lambdaQuery()
                    .eq(WmNewsMaterial::getNewsId,wmNews.getId()));

            //2. 修改文章信息
            updateById(wmNews);

        }else{
            //新增
            wmNews.setCreatedTime(new Date());
            save(wmNews);
        }
    }
}
